/*
 *    Copyright 2012 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package net.developerstation.mybatis.caches.redis.builder;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * Converter from the Config to a proper {@link RedisConfiguration}.
 *
 * @author Simone Tripodi
 */
public final class RedisConfigurationBuilder {

    /**
     * This class instance.
     */
    private static final RedisConfigurationBuilder INSTANCE = new RedisConfigurationBuilder();

    private static final String SYSTEM_PROPERTY_REDIS_PROPERTIES_FILENAME = "redis.properties.filename";

    /**
     *
     */
    private static final String JEDIS_RESOURCE = "redis.properties";

    private final String jedisPropertiesFilename;

    /**
     * Return this class instance.
     *
     * @return this class instance.
     */
    public static RedisConfigurationBuilder getInstance() {
        return INSTANCE;
    }

    /**
     * The setters used to extract properties.
     */
    private final List<AbstractPropertySetter<?>> settersRegistry = new ArrayList<AbstractPropertySetter<?>>();

    /**
     * Hidden constructor, this class can't be instantiated.
     */
    private RedisConfigurationBuilder() {
        jedisPropertiesFilename = System.getProperty(SYSTEM_PROPERTY_REDIS_PROPERTIES_FILENAME, JEDIS_RESOURCE);

        settersRegistry.add(new StringPropertySetter("redis.host", "host", "127.0.0.1"));
        settersRegistry.add(new IntegerPropertySetter("redis.port", "port", 6379));
        settersRegistry.add(new StringPropertySetter("redis.password", "password",null));
        settersRegistry.add(new IntegerPropertySetter("redis.timeout", "timeout", 5));
        settersRegistry.add(new IntegerPropertySetter("redis.database", "database", 0));
        settersRegistry.add(new StringPropertySetter("redis.clientName", "clientName","_jedis_"));
        
        settersRegistry.add(new IntegerPropertySetter("redis.maxTotal", "maxTotal", -1));
        settersRegistry.add(new IntegerPropertySetter("redis.maxIdle", "maxIdle", 2000));
        settersRegistry.add(new IntegerPropertySetter("redis.maxWaitMillis", "maxWaitMillis", 100));
        settersRegistry.add(new IntegerPropertySetter("redis.minEvictableIdleTimeMillis", "minEvictableIdleTimeMillis", 864000000));
        settersRegistry.add(new IntegerPropertySetter("redis.minIdle", "minIdle", 1000));
        settersRegistry.add(new IntegerPropertySetter("redis.numTestsPerEvictionRun", "numTestsPerEvictionRun", 10));
        settersRegistry.add(new BooleanPropertySetter("redis.lifo", "lifo", false));
        settersRegistry.add(new IntegerPropertySetter("redis.softMinEvictableIdleTimeMillis", "softMinEvictableIdleTimeMillis", 10));
        settersRegistry.add(new BooleanPropertySetter("redis.testOnBorrow", "testOnBorrow", true));
        settersRegistry.add(new BooleanPropertySetter("redis.testOnReturn", "testOnReturn", false));
        settersRegistry.add(new BooleanPropertySetter("redis.testWhileIdle", "testWhileIdle", false));
        settersRegistry.add(new IntegerPropertySetter("redis.timeBetweenEvictionRunsMillis", "timeBetweenEvictionRunsMillis", 300000));
        settersRegistry.add(new BooleanPropertySetter("redis.blockWhenExhausted", "blockWhenExhausted", true));
        
        
//        settersRegistry.add(new TimeUnitSetter());

    }

    /**
     * Parses the Config and builds a new {@link RedisConfiguration}.
     *
     * @return the converted {@link RedisConfiguration}.
     */
    public RedisConfiguration parseConfiguration() {
        return parseConfiguration(getClass().getClassLoader());
    }

    /**
     * Parses the Config and builds a new {@link RedisConfiguration}.
     *
     * @param the {@link ClassLoader} used to load the {@code memcached.properties} file in classpath.
     * @return the converted {@link RedisConfiguration}.
     */
    public RedisConfiguration parseConfiguration(ClassLoader classLoader) {
        Properties config = new Properties();

        // load the properties specified from /memcached.properties, if present
        InputStream input = classLoader.getResourceAsStream(jedisPropertiesFilename);
        if (input != null) {
            try {
                config.load(input);
            } catch (IOException e) {
                throw new RuntimeException("An error occurred while reading classpath property '"
                        + jedisPropertiesFilename
                        + "', see nested exceptions", e);
            } finally {
                try {
                    input.close();
                } catch (IOException e) {
                    // close quietly
                }
            }
        }

        RedisConfiguration memcachedConfiguration = new RedisConfiguration();

        for (AbstractPropertySetter<?> setter : settersRegistry) {
            setter.set(config, memcachedConfiguration);
        }

        return memcachedConfiguration;
    }

}
